package gria

import org.apache.axis.message.MessageElement;
import org.apache.axis.message.addressing.EndpointReferenceType;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import uk.ac.soton.itinnovation.grid.types.MatchPattern;
import uk.ac.soton.itinnovation.grid.types.PolicyRule;
import uk.ac.soton.ecs.iam.grid.comms.client.RemoteDataService;
import uk.ac.soton.ecs.iam.grid.comms.client.DataConversation;
import uk.ac.soton.itinnovation.grid.types.ConversationID;
import uk.ac.soton.ecs.iam.grid.comms.client.JobConversation;
import uk.ac.soton.ecs.iam.grid.comms.client.RemoteJobService;
import uk.ac.soton.itinnovation.grid.types.ConversationID;

import simpleauth.User

class GriaJobController {
    
    def beforeInterceptor = [action:this.&checkUser,except:
    ['index','show','login','doLogin']]
   
    def checkUser() {
        if(!session.user) {
            // i.e. user not logged in
            flash['from'] = 'griaJob'
            redirect(controller:'user',action:'login')
            return false
        }
    }
    
    def index = { redirect(action:list,params:params) }

    // the delete, save and update actions only accept POST requests
    def allowedMethods = [delete:'POST', save:'POST', update:'POST']

    def list = {
        if(!params.max) params.max = 10
        [ griaJobList: GriaJob.list( params ) ]
    }

    def show = {
        for (test in gria.GriaFile.findWhere(type:gria.FileType.findWhere(type:"BAC File")))
        {
        println test
        }
        
        def griaJob = GriaJob.get( params.id )

        if(!griaJob) {
            flash.message = "GriaJob not found with id ${params.id}"
            redirect(action:list)
        }
        else { return [ griaJob : griaJob ] }
    }

    def delete = {
        def griaJob = GriaJob.get( params.id )
        if(griaJob) {
            griaJob.delete()
            flash.message = "GriaJob ${params.id} deleted"
            redirect(action:list)
        }
        else {
            flash.message = "GriaJob not found with id ${params.id}"
            redirect(action:list)
        }
    }

    def edit = {
        def griaJob = GriaJob.get( params.id )

        if(!griaJob) {
            flash.message = "GriaJob not found with id ${params.id}"
            redirect(action:list)
        }
        else {
            return [ griaJob : griaJob ]
        }
    }

    def update = {
        def griaJob = GriaJob.get( params.id )
        if(griaJob) {
            griaJob.properties = params
            if(!griaJob.hasErrors() && griaJob.save()) {
                flash.message = "GriaJob ${params.id} updated"
                redirect(action:show,id:griaJob.id)
            }
            else {
                render(view:'edit',model:[griaJob:griaJob])
            }
        }
        else {
            flash.message = "GriaJob not found with id ${params.id}"
            redirect(action:edit,id:params.id)
        }
    }
    
    
    //refresh the status of the gria job
    def updateStatus = {
        def griaJob = GriaJob.get( params.id )
        if(griaJob) {
            EndpointReferenceType jobEPR = ConversationID.getEPR(griaJob.application.serviceAddress.substring(0,griaJob.application.serviceAddress.length()-5), griaJob.resourceID)
            JobConversation jc = session.user.helperProxyFactory.createProxy(jobEPR, JobConversation.class) 
            griaJob.status = jc.checkJob().getProcessState();    
            if (griaJob.status.equalsIgnoreCase("ready") && !griaJob.finished )
            {
                int index = 0;
                boolean allOutputsFull = false;
                for (output in griaJob.application.outputs)
                {
                def fileType = FileType.findWhere(type:output)
                def dataCon = jc.getOutputs()[index]
                def containsData = dataCon.checkData().getContainsData();       
                allOutputsFull = (!allOutputsFull & containsData) || (allOutputsFull & containsData)
                if (containsData)
                {                
                    println "Data Con contains data!"  
                    GriaFile outFile = new GriaFile()
                    outFile.serviceAddress = dataCon.getEPR().getAddress().toString();
                    outFile.resourceID = ((MessageElement)dataCon.getEPR().getParameters().get(0)).getChildNodes().item(0).toString();
                    outFile.created = new Date()
                    outFile.owner = User.findWhere(userName:session.User)
                    outFile.type = fileType
                    outFile.fileName = outFile.type.defaultName + outFile.type.extension
                    outFile.description = fileType.description
                    if (!outFile.save())
                        {
                          outFile.errors.each {
                             println it
                          } 
                        }
                    griaJob.addToOutputs(outFile)         
                }  
                index++;
                }
                if(allOutputsFull)
                {
                griaJob.finished = true;
                griaJob.outputReady = true;    
                }
            }
            if (griaJob.finished)
            {
            griaJob.status = "Finished"
            }
            
            if(!griaJob.hasErrors() && griaJob.save()) {
                flash.message = "GriaJob ${params.id} updated"
                redirect(action:show,id:griaJob.id)
            }
            else {
                render(view:'show',model:[griaJob:griaJob])
            }
        }
        else {
            flash.message = "GriaJob not found with id ${params.id}"
            redirect(action:show,id:params.id)
        }
    }

    def create = {
        def griaJob = new GriaJob()
        griaJob.properties = params
        return ['griaJob':griaJob]
    }

    def save = {
        params['owner'] = User.findWhere(userName:params['owner'])
        params['created'] = new Date();
        params['status'] = "New"
        println params['application'].id
        GriaApplication application = GriaApplication.get(params['application'].id)
        
        
        RemoteJobService jobService = (RemoteJobService) session.user.serviceFactory.createServiceProxy(application.serviceAddress);    
        JobConversation cnv = jobService.createJob(application.applicationString, params['application'].id);
         
        params['resourceID'] = ((MessageElement)cnv.getEPR().getParameters().get(0)).getChildNodes().item(0).toString();
      
        def griaJob = new GriaJob(params)
        
        // create the griaFile objects for the job
        // these get bound to data stagers later
 //       for ( input in application.inputs ) {
    //        GriaFile griaFile = new GriaFile()
    //        griaFile.type = input
    //        griaFile.save()
   //         griaJob.addToInputs(griaFile)
            
   //     }
   //     for ( output in application.outputs ) {
   //         GriaFile griaFile = new GriaFile()
   //         griaFile.type = output
   //         griaFile.save()
   //         griaJob.addToOutputs(griaFile)
   //     }

        
        if(!griaJob.hasErrors() && griaJob.save()) {
            flash.message = "GriaJob ${griaJob.id} created"
            redirect(action:show,id:griaJob.id)
        }
        else {
            render(view:'create',model:[griaJob:griaJob])
        }
    } 
    
    def upload = {   
         println "upload"
         def f = request.getFile('file')
         if(!f.empty) {
                File stagedFile = new File(grailsApplication.config.gria.identity.tempFileDir + f.getOriginalFilename());
                f.transferTo(stagedFile);
                RemoteDataService dataService = (RemoteDataService) session.user.serviceFactory.createServiceProxy(grailsApplication.config.gria.services.dataService);
                DataConversation dataconv = dataService.createStagingArea(request.getParameter('description'));
                dataconv.saveFromFile(stagedFile);      
                System.out.println("Add: " + dataconv.getEPR().getAddress());
                params['fileName'] =  f.getOriginalFilename();
                params['serviceAddress'] = dataconv.getEPR().getAddress().toString();
                params['resourceID'] = ((MessageElement)dataconv.getEPR().getParameters().get(0)).getChildNodes().item(0).toString();
                stagedFile.delete();        
            }    
         else {
                flash.message = 'file cannot be empty'
                redirect(action:'create')
             }
        params['owner'] = session.user
        params['created'] = new Date();
        params['type'] = FileType.findWhere(type:request.getParameter('type'))
        params['notes'] = "Test Message"
        
        def griaFile = new GriaFile(params)
        if(!griaFile.hasErrors() && griaFile.save()) {
            flash.message = "GriaFile ${griaFile.id} created"
            def griaJob = GriaJob.get(request.getParameter('jobid'))
            //see if the input already has a file of this type
            //if so remove it
            //NOTE:- this is assuming only one of each
            //type of file is valid.
            def remove
            for (x in griaJob.inputs)
            {
                if (x.type == griaFile.type)
                {
                 println "Removing existing"
                 remove = x;
                }
            }
            if (remove)
                griaJob.inputs.remove(remove)
        
            //now update the job
            griaJob.addToInputs(griaFile);
            griaJob.save();
            redirect(action:'show', id:request.getParameter('jobid'))
        }
        else {
             griaFile.errors.each {
                println it
            } 
            render("FAIL")
        }
    }
    
    def updateFile = {
       def newFile = GriaFile.get(request.getParameter("fileid"))
       def griaJob = GriaJob.get(request.getParameter("jobid"))
       
       //see if the input already has a file of this type
       //if so remove it
       //NOTE:- this is assuming only one of each
       //type of file is valid.
       def remove
       for (x in griaJob.inputs)
       {
        if (x.type == newFile.type)
        {
            println "Removing existing"
            remove = x;
        }
       }
       if (remove)
        griaJob.inputs.remove(remove)
        
       //now update the job
       griaJob.addToInputs(newFile);
       griaJob.save();
     
       render(contentType:"text/html", text:"<g:linkcontroller='griaFile' action='show' id='${newFile.id}'>${newFile.encodeAsHTML()}</g:link>")

    }
    
    def updateArgs = {
       def griaJob = GriaJob.get(request.getParameter("jobid"))
       
       for (par in request.getParameterNames()){
           if (ApplicationArgument.findWhere(name:par))
           {
           boolean existing = false;
           def appArg = ApplicationArgument.findWhere(name:par)
           
           //got valid argument
           def value = request.getParameter(par)
           
           //see if the argument has been set before
           for (existing_set_args in griaJob.arguments)
           {
                if (existing_set_args.type == appArg)
                {
                    existing = true;
                    existing_set_args.value = value;
                    existing_set_args.save();
                }
                
            }
            if (!existing)
            {
                JobArgumentValue newArg = new JobArgumentValue(value:value, job:griaJob, type:appArg)
                newArg.save()
   
            
            }
           }
           } 
        griaJob.save();
       render "Saved"

    }
    
 
    def submitJob = {
        JobConversation jc;
        def griaJob = GriaJob.get(request.getParameter("id"))
        if(griaJob) {
            //creating the epr with ?wsdl on the service address seems to cause problems. 
            //remove it for now
            EndpointReferenceType jobEPR = ConversationID.getEPR(griaJob.application.serviceAddress.substring(0,griaJob.application.serviceAddress.length()-5), griaJob.resourceID)
            jc = session.user.helperProxyFactory.createProxy(jobEPR, JobConversation.class) 
             
        }
        else {
            flash.message = "Gria Job job not found with id ${params.id}"
            redirect(action:show,id:params.id)
        } 
        
        int counter = 0;
        for (input in griaJob.application.inputs)
        {
            println("Input " + input)
            boolean found = false
            //check to see if a stager has been selected - if not then we can't submit the job
            if (!griaJob.inputs.isEmpty()){    
                println "not empty"          
                for (griaFile in griaJob.inputs)
                {
                    println "Gria file " + griaFile
                    if (griaFile.type.type == input)
                    {                  
                      found = true;
                      EndpointReferenceType fileERP = ConversationID.getEPR(griaFile.serviceAddress, griaFile.resourceID)
                      println (" SA = " + griaFile.serviceAddress);
                      println (" RD = " + griaFile.resourceID);
                      jc.getInputs()[counter].copyFrom(fileERP)
                    }
                }
            }
          if (!found)
          {
            flash.message = "Please select all of the input files"
            redirect(action:show,id:params.id)
          }
           counter++
        }
           
        jc.startJob(null)
        
        griaJob.status="Running"

        if(!griaJob.hasErrors() && griaJob.save()) {
            flash.message = "griaJob ${griaJob.id} Submitted"
            redirect(action:show,id:griaJob.id)
        }
        else {
            render(view:'show',model:[griaJob:griaJob])
        }
    }
    
    //fetch the job log and display it
    def viewLog = {
        def griaJob = GriaJob.get(request.getParameter("id"))
        if(griaJob) {
            EndpointReferenceType jobEPR = ConversationID.getEPR(griaJob.application.serviceAddress.substring(0,griaJob.application.serviceAddress.length()-5), griaJob.resourceID)
            JobConversation jc = session.user.helperProxyFactory.createProxy(jobEPR, JobConversation.class) 
   
            flash.log = jc.checkJob().getLogText();    
            render(view:'view',model:[griaJob:griaJob])       
        }
        else {
            flash.message = "GRIA job not found with id ${params.id}"
            redirect(action:show,id:params.id)
        }
    }
   
}
